/*************************************************************************
	> File Name: RingQueue.hpp
	> Author: H.M. Lau
	> Mail: hm.lau@outlook.com
	> Created Time: 2023/09/28 16:39
 ************************************************************************/

#pragma once

#include "comm.hpp"
#include "Sem.hpp"
#include "LockGuard.hpp"

template<class T>
class RingQueue
{
public:
    RingQueue (int capacity = gDefaultCap)
        :_capacity(capacity)
        ,_pPos(0)
        ,_cPos(0)
        ,_spaceSem(capacity)
        ,_dataSem(0)
        ,_rq(capacity)
    {
        pthread_mutex_init(&_plock, nullptr);
        pthread_mutex_init(&_clock, nullptr);
    }

    void push(const T &in)
    {
        _spaceSem.p();
        {
            LockGuard lockGuard(&_plock);
            _rq[_pPos++] = in;
            _pPos %= _capacity;
        }
        _dataSem.v();
    }

    void pop(T *out)
    {
        _dataSem.p();
        {
           LockGuard lockGuard(&_clock);
            *out = _rq[_cPos++];
            _cPos %= _capacity;
        }
        _spaceSem.v();
    }

private:
    int _capacity;
    int _pPos;
    int _cPos;
    pthread_mutex_t _plock;
    pthread_mutex_t _clock;
    Sem _spaceSem;
    Sem _dataSem;
    std::vector<T> _rq;
};
